﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Resources;

namespace DirectorySlicer
{
    /// <summary>
    /// thread to copy/link the files
    /// </summary>
    class workerThread
    {
        private Form1 form;
        private Thread readerThread;
        private FileCollector collector;
        private String comboBox_KindOfSizeText;
        private String textBox_sizeText;
        private String textBox_sourcePathText;
        private String textBox_destPathText;
        private bool makeHardLinks;

        /// <summary>
        /// constructor.
        /// </summary>
        /// <param name="form">form, to invoke the update the progressBar</param>
        /// <param name="readerThread">thread, which collects files</param>
        /// <param name="collector">object, which is stored in the thread</param>
        /// <param name="comboBox_KindOfSizeText">components to get information which kind of size was selected</param>
        /// <param name="textBox_sizeText">component to get information how much size was selected</param>
        /// <param name="textBox_sourcePathText">source path</param>
        /// <param name="textBox_destPathText">destination folder</param>
        /// <param name="makeHardLinks">if true, then use hardlinks</param>
        public workerThread(Form1 form, Thread readerThread, FileCollector collector, String comboBox_KindOfSizeText, String textBox_sizeText, String textBox_sourcePathText, String textBox_destPathText, bool makeHardLinks)
        {
            this.form = form;
            this.readerThread = readerThread;
            this.collector = collector;
            this.comboBox_KindOfSizeText = comboBox_KindOfSizeText;
            this.textBox_sizeText = textBox_sizeText;
            this.textBox_sourcePathText = textBox_sourcePathText;
            this.textBox_destPathText = textBox_destPathText;
            this.makeHardLinks = makeHardLinks;
        }
        public void gogo()
        {
            //used data
            List<FileContainer> files;
            convertToByte convToByte;
            convertFromByte convFromByte;
            long maxSize = 0;
            long sizeSetInByte;
            float sizeSet;
            FilesBinPackerAndCopy packer;

            //start processing

            form.Invoke(new Logger.UpdateLogCallback(Logger.Log), "scanning files ...");

            //wait for thread to finish collcting files
            readerThread.Join();
            //get the file list
            files = collector.getFileList();
            form.Invoke(new Logger.UpdateProgressSettingCallback(Logger.progressBarSet), files.Count);
            //calculate the target size of bins
            switch (comboBox_KindOfSizeText)
            {
                case "MB":
                    convToByte = new convertToByte(convertMBToByte);
                    convFromByte = new convertFromByte(convertByteToMB);
                    break;
                case "GB":
                    convToByte = new convertToByte(convertGBToByte);
                    convFromByte = new convertFromByte(convertByteToGB);
                    break;
                case "TB":
                    convToByte = new convertToByte(convertTBToByte);
                    convFromByte = new convertFromByte(convertByteToTB);
                    break;
                default:
                    form.Invoke(new Logger.UpdateLogCallback(Logger.Log), "ERROR: unknown type of size \"" + comboBox_KindOfSizeText + "\"");
                    form.Invoke(new Form1.button_START_Click_CALL(form.button_START_Click), null, null);
                    return;
            }
            foreach (FileContainer f in files)
                if (f.getSize() > maxSize)
                    maxSize = f.getSize();
            form.Invoke(new Logger.UpdateLogCallback(Logger.Log), "size of largest file: " + convFromByte(maxSize) + comboBox_KindOfSizeText);
            sizeSet = (float)Double.Parse(textBox_sizeText.Replace('.', ','));
            sizeSetInByte = convToByte(sizeSet);
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
            //if largest file is larger then selected size: error dialog
            if (maxSize > sizeSetInByte)
            {
                form.Invoke(new Form1.showMessageBoxCALL(form.showMessageBox), resources.GetString("sizeDialog_Text"), resources.GetString("sizeDialog_Heading"), MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                form.Invoke(new Form1.button_START_Click_CALL(form.button_START_Click),null, null);
                return;
            }
            packer = new FilesBinPackerAndCopy(files, textBox_sourcePathText, textBox_destPathText, sizeSetInByte, form, makeHardLinks);
            form.Invoke(new Logger.UpdateLogCallback(Logger.Log), "calculating partitions...");
            //calculate and copy the bins as calculated
            packer.binPackAndCopy();
            form.Invoke(new Form1.showMessageBoxCALL(form.showMessageBox), resources.GetString("readyDialog_Text"), resources.GetString("readyDialog_Heading"), MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
            form.Invoke(new Form1.button_START_Click_CALL(form.button_START_Click), null, null);
        }

        private delegate float convertFromByte(long size);
        private delegate long convertToByte(float size);

        /*
         * converter functions
         */
        public static float convertByteToMB(long size)
        {
            return size / (1000f * 1000f);
        }
        public static float convertByteToGB(long size)
        {
            return size / (1000f * 1000f * 1000f);
        }
        public static float convertByteToTB(long size)
        {
            return size / (1000f * 1000f * 1000f * 1000f);
        }
        public static long convertMBToByte(float size)
        {
            return (long)(size * 1000 * 1000);
        }
        public static long convertGBToByte(float size)
        {
            return (long)(size * 1000 * 1000 * 1000);
        }
        public static long convertTBToByte(float size)
        {
            return (long)(size * 1000 * 1000 * 1000 * 1000);
        }
    }
}
